using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace DotNetGear.Drawing
{
    public class PathFinder
    {
        private byte[] _argbValues;
        int _width, _height;

        public PathFinder(Bitmap bmp)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb) throw new NotSupportedException("PixelFormat other than 32bppArgb is not supported."); 
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            int bytes = bmp.Width * bmp.Height * 4;
            _width = bmp.Width;
            _height = bmp.Height;
            _argbValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, _argbValues, 0, bytes);
            bmp.UnlockBits(bmpData);
        }

        public GraphicsPath GetPath(Color colorTransparent)
        {
            Point[,] points = new Point[_width, _height];
            int num3 = 0;
            for (int i = 0; i < _width; i++)
            {
                for (int k = 0; k < _height; k++)
                {
                    int num7;
                    if (GetPixel(i, k).ToArgb() != colorTransparent.ToArgb())
                    {
                        if (!GetNearColor(i, k, colorTransparent))
                        {
                            (points[i, k]) = new Point(i, k);
                            num3++;
                        }
                        else
                        {
                            points[i, k].Y = (num7 = -2);
                            points[i, k].X = (num7);
                        }
                    }
                    else
                    {
                        points[i, k].Y = (num7 = -2);
                        points[i, k].X = (num7);
                    }
                }
            }
            Point[] point = new Point[num3];
            GraphicsPath path = new GraphicsPath();
            point[0] = GetFirst(_width, _height, points);
            for (int j = 1; j < num3; j++)
            {
                point[j] = GetNearPoint(_width, _height, point, j - 1, points);
                if ((point[j].X == point[0].X) && (point[j].Y == point[0].Y))
                {
                    num3 = j;
                    break;
                }
            }
            path.AddPolygon(point);
            return path;
        }
  
        private Color GetPixel(int x, int y)
        {
            long i = (x + y * _width) * 4;
            return Color.FromArgb(_argbValues[i + 3], _argbValues[i + 2], _argbValues[i + 1], _argbValues[i]);
        }

        private static Point GetFirst(int width, int height, Point[,] points)
        {
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    if ((points[j, i].X != -2) || (points[j, i].Y != -2))
                    {
                        return (points[j, i]);
                    }
                }
            }
            return new Point(-2, -2);
        }

        private bool GetNearColor(int x, int y, Color colorTransparent)
        {
            if (y > 1)
            {
                Color pixel = GetPixel(x, y - 1);
                int num = colorTransparent.ToArgb();
                if ((((pixel.ToArgb() != num) && (x > 1)) && ((GetPixel(x - 1, y).ToArgb() != num) && (y < (_height - 1)))) && (((GetPixel(x, y + 1).ToArgb() != num) && (x < (_width - 1))) && (GetPixel(x + 1, y).ToArgb() != num)))
                {
                    return true;
                }
            }
            return false;
        }

        private static Point GetNearPoint(int width, int height, Point[] point, int index, Point[,] points)
        {
            for (int i = point[index].X + 1; i >= (point[index].X - 1); i--)
            {
                for (int j = point[index].Y - 1; j <= (point[index].Y + 1); j++)
                {
                    if (((((i < 0) || (i >= width)) || (j < 0)) || (j >= height)) || ((points[i, j].X == -2) || (points[i, j].Y == -2)))
                    {
                        continue;
                    }
                    bool flag = false;
                    for (int k = index; k > 0; k--)
                    {
                        if ((point[k].X == i) && (point[k].Y == j))
                        {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag)
                    {
                        return (points[i, j]);
                    }
                }
            }
            return new Point(-2, -2);
        }
  }
}
